package com.wj.service.impl;

import com.wj.domain.entity.BookCacheEntity;
import com.wj.domain.vo.BookCacheVO;
import com.wj.domain.vo.BookVO;
import com.wj.domain.vo.ChapterContentVO;
import com.wj.domain.vo.ChapterVO;
import com.wj.infrastructure.mapper.BookCacheMapper;
import com.wj.infrastructure.mapper.ChapterMapper;
import com.wj.infrastructure.repository.BookCacheRepository;
import com.wj.service.BookCacheService;
import com.wj.service.BookService;
import com.wj.service.ChapterContentService;
import com.wj.tool.common.exception.SelfException;
import com.wj.tool.common.utils.CollectionUtils;
import com.wj.tool.common.utils.UuidUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service
@Slf4j
public class BookCacheServiceImpl implements BookCacheService {

    @Resource
    private BookCacheRepository bookCacheRepository;

    @Resource
    private ChapterMapper chapterMapper;

    @Resource
    private ChapterContentService chapterContentService;

    @Resource
    private BookService bookService;

    @Value("${file.absopath_pre}")
    private String file_absopath_pre;

    @Value("${file.realpath_pre}")
    private String file_realpath_pre;

    @Resource
    private BookCacheMapper bookCacheMapper;

    @Override
    public BookCacheVO getCacheByBookId(Long bookId) {
        BookCacheEntity bookCacheEntity = bookCacheRepository.findByBookId(bookId);
        if (bookCacheEntity == null){
            throw new SelfException("该书籍未缓存");
        }
        BookCacheVO bookCacheVO = new BookCacheVO();
        bookCacheVO.setBookName(bookCacheEntity.getBookName());
        bookCacheVO.setAbsolutePath(bookCacheEntity.getAbsolutePath());
        bookCacheVO.setRelativePath(bookCacheEntity.getRelativePath());
        return bookCacheVO;
    }

    @Override
    @Async
    @Transactional(rollbackFor = Exception.class)
    public void createBookFile(Long bookId, String bookName) {
        FileOutputStream outStr = null;
        BufferedOutputStream buff = null;
        String oldPath = "";
        //设置响应头，对文件进行url编码
//            String bookNameStr = URLEncoder.encode(bookName, "UTF-8");

        //查看书籍缓存
        BookCacheEntity bookCacheEntity = bookCacheRepository.findByBookId(bookId);

        SimpleDateFormat sdf = new SimpleDateFormat("YYYYMMddHHmmss");
        String newFileName =  sdf.format(new Date()) + ".txt";
        //存储路径
        String fileAbsoPath = file_absopath_pre + bookName + "/" + bookName + newFileName;

        String fileRealpath = file_realpath_pre + bookName + "/" + bookName + newFileName;
        File newFile = new File(fileAbsoPath);
        // 检测是否存在目录
        if (!newFile.getParentFile().exists()){
            newFile.getParentFile().mkdirs();
        }

        try {
            outStr = new FileOutputStream(new File(fileAbsoPath));
        } catch (FileNotFoundException e) {
            throw new SelfException("生成输出流出错:"+e);
        }

        buff = new BufferedOutputStream(outStr);
        List<ChapterVO> chapterList = new ArrayList<>();
        if (bookCacheEntity == null){
            bookCacheEntity = new BookCacheEntity();
            bookCacheEntity.setId(UuidUtils.createId());
            bookCacheEntity.setBookId(bookId);
            bookCacheEntity.setBookName(bookName);
            chapterList = chapterMapper.queryListByBookId(bookId);
        } else {
            oldPath = bookCacheEntity.getAbsolutePath();
            // 老文件复制
            File oldFile = new File(oldPath);
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(oldFile);
                BufferedInputStream bis = new BufferedInputStream(fis);
                copyFile(bis, buff);
            } catch (Exception e) {
                throw new SelfException("复制老文件输入流出错:"+e);
            }

            chapterList = chapterMapper.queryListByBookIdAndFromChapterId(bookId, bookCacheEntity.getChapterId());
            oldFile.delete();
        }
        bookCacheEntity.setAbsolutePath(fileAbsoPath);
        bookCacheEntity.setRelativePath(fileRealpath);

        int i = 0;
        double k = 0.0;
        int size = chapterList.size();
        SimpleDateFormat sd = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
        if (CollectionUtils.isNotEmpty(chapterList)){
            log.info("开始缓存："+bookName+",一共"+chapterList.size()+"章，当前时间"+sd.format(new Date()));
            for (ChapterVO chapterVO:chapterList){
                Long contentId = chapterVO.getContentId();
                ChapterContentVO chapterContent=chapterContentService.getById(contentId);
                String content = chapterContent.getContent();
                String chapterName = chapterVO.getChapterTitle();
                try {
                    buff.write(chapterName.getBytes(StandardCharsets.UTF_8));
                    buff.write("\n".getBytes(StandardCharsets.UTF_8));
                    content = content
//                            .replaceAll(Constants.CONTENT_AD_PATTERN, "")
                            .replaceAll("<br\\s*/*>", "\r\n")
                            .replaceAll("&nbsp;", " ")
                            .replaceAll("<a[^>]*>", "")
                            .replaceAll("</a>", "")
                            .replaceAll("<div[^>]*>", "")
                            .replaceAll("</div>", "")
                            .replaceAll("<p[^>]*>[^<]*<a[^>]*>[^<]*</a>\\s*</p>", "")
                            .replaceAll("<p[^>]*>", "")
                            .replaceAll("</p>", "\r\n");
                    buff.write(content.getBytes(StandardCharsets.UTF_8));
                    buff.write("\r\n".getBytes(StandardCharsets.UTF_8));
                    buff.write("\r\n".getBytes(StandardCharsets.UTF_8));
                    buff.flush();
                } catch (IOException e) {
                    throw new SelfException("写入流时出错:"+e);
                }

                double thisChapterSortD = Math.ceil(size * k);
                int thisChapterSort = (int) thisChapterSortD;
                if (i == thisChapterSort){
                    int process = (int) (k * 100);
                    log.info(bookName+"缓存进度："+process+"%");
                    k+=0.1;
                }
                i++;
            }
        }

        if (CollectionUtils.isNotEmpty(chapterList)){
            int maxIndex = chapterList.size() -1;
            Long maxChapterId = chapterList.get(maxIndex).getId();
            String maxChapterTitle = chapterList.get(maxIndex).getChapterTitle();
            bookCacheEntity.setChapterId(maxChapterId);
            bookCacheEntity.setChapterTitle(maxChapterTitle);
        }
        bookCacheEntity.setCacheTime(new Date());;
        bookCacheRepository.save(bookCacheEntity);
        try {
            buff.close();
            outStr.close();
        } catch (IOException e) {
            throw new SelfException("关闭流出错："+e);
        }
        log.info(bookName+"缓存完成，当前时间："+sd.format(new Date()));

    }

    @Override
    public void createNewBookFile() {
        List<BookVO> list = getCacheBookList();
        int size = list.size();
        ExecutorService executor = Executors.newFixedThreadPool(2);
        CountDownLatch countDownLatch = new CountDownLatch(size);
        for (int i = 0; i < size; i++) {
            BookVO bookVO = list.get(i);
            log.info("--------------开启第" + (i + 1) + "个线程");
            CreateBookFileThread createBookFileThread = new CreateBookFileThread(countDownLatch, bookVO);
            executor.execute(createBookFileThread);
        }
        //主程序执行到await()函数会阻塞等待线程的执行，直到计数为0
        try {
            countDownLatch.await();
        } catch (Exception e){
            throw new SelfException("生成txt出错："+e);
        }

    }

    class CreateBookFileThread implements Runnable {
        CountDownLatch countDownLatch;
        private BookVO bookVO;

        public CreateBookFileThread(CountDownLatch countDownLatch, BookVO bookVO){
            this.countDownLatch = countDownLatch;
            this.bookVO = bookVO;
        }

        @Override
        public void run() {
            Long bookId = bookVO.getId();
            String bookName = bookVO.getBookName();
            FileOutputStream outStr = null;
            BufferedOutputStream buff = null;
            String oldPath = "";
            //查看书籍缓存
            BookCacheEntity bookCacheEntity = bookCacheRepository.findByBookId(bookId);

            SimpleDateFormat sdf = new SimpleDateFormat("YYYYMMddHHmmss");
            String newFileName =  sdf.format(new Date()) + ".txt";
            //存储路径
            String fileAbsoPath = file_absopath_pre + bookName + "/" + bookName + newFileName;

            String fileRealpath = file_realpath_pre + bookName + "/" + bookName + newFileName;

            try {
                File newFile = new File(fileAbsoPath);
                // 检测是否存在目录
                if (!newFile.getParentFile().exists()){
                    newFile.getParentFile().mkdirs();
                }

                try {
                    outStr = new FileOutputStream(new File(fileAbsoPath));
                } catch (FileNotFoundException e) {
                    throw new SelfException("创建输出流时出错："+e);
                }

                buff = new BufferedOutputStream(outStr);
                List<ChapterVO> chapterList = new ArrayList<>();
                if (bookCacheEntity == null){
                    bookCacheEntity = new BookCacheEntity();
                    bookCacheEntity.setId(UuidUtils.createId());
                    bookCacheEntity.setBookId(bookId);
                    bookCacheEntity.setBookName(bookName);
                    chapterList = chapterMapper.queryListByBookId(bookId);
                } else {
                    oldPath = bookCacheEntity.getAbsolutePath();
                    File oldFile = new File(oldPath);
                    // 判断老文件是否存在
                    if (!oldFile.getParentFile().exists()){
                        chapterList = chapterMapper.queryListByBookId(bookId);
                    } else {
                        // 老文件复制
                        FileInputStream fis = null;
                        try {
                            fis = new FileInputStream(oldFile);
                            BufferedInputStream bis = new BufferedInputStream(fis);
                            copyFile(bis, buff);
                        } catch (Exception e) {
                            throw new SelfException("复制老文件到输入流时出错："+e);
                        }
                        chapterList = chapterMapper.queryListByBookIdAndFromChapterId(bookId, bookCacheEntity.getChapterId());
                        oldFile.delete();
                    }

                }
                bookCacheEntity.setAbsolutePath(fileAbsoPath);
                bookCacheEntity.setRelativePath(fileRealpath);

                int i = 0;
                double k = 0.0;
                int size = chapterList.size();
                SimpleDateFormat sd = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
                if (CollectionUtils.isNotEmpty(chapterList)){
                    log.info("开始缓存："+bookName+",一共"+chapterList.size()+"章，当前时间"+sd.format(new Date()));
                    for (ChapterVO chapterVO:chapterList){
                        Long contentId = chapterVO.getContentId();
                        ChapterContentVO chapterContent=chapterContentService.getById(contentId);
                        if (chapterContent == null){
                            throw new SelfException("该章节内容不存在:"+contentId);
                        }
                        String content = chapterContent.getContent();
                        String chapterName = chapterVO.getChapterTitle();
                        try {
                            buff.write(chapterName.getBytes(StandardCharsets.UTF_8));
                            buff.write("\n".getBytes(StandardCharsets.UTF_8));
                            content = content
//                            .replaceAll(Constants.CONTENT_AD_PATTERN, "")
                                    .replaceAll("<br\\s*/*>", "\r\n")
                                    .replaceAll("&nbsp;", " ")
                                    .replaceAll("<a[^>]*>", "")
                                    .replaceAll("</a>", "")
                                    .replaceAll("<div[^>]*>", "")
                                    .replaceAll("</div>", "")
                                    .replaceAll("<p[^>]*>[^<]*<a[^>]*>[^<]*</a>\\s*</p>", "")
                                    .replaceAll("<p[^>]*>", "")
                                    .replaceAll("</p>", "\r\n");
                            buff.write(content.getBytes(StandardCharsets.UTF_8));
                            buff.write("\r\n".getBytes(StandardCharsets.UTF_8));
                            buff.write("\r\n".getBytes(StandardCharsets.UTF_8));
                            buff.flush();
                        } catch (IOException e) {
                            throw new SelfException("写文件流时出错"+e);
                        }

                        double thisChapterSortD = Math.ceil(size * k);
                        int thisChapterSort = (int) thisChapterSortD;
                        if (i == thisChapterSort){
                            int process = (int) (k * 100);
                            log.info(bookName+"缓存进度："+process+"%");
                            k+=0.1;
                        }
                        i++;
                    }
                }

                if (CollectionUtils.isNotEmpty(chapterList)){
                    int maxIndex = chapterList.size() -1;
                    Long maxChapterId = chapterList.get(maxIndex).getId();
                    String maxChapterTitle = chapterList.get(maxIndex).getChapterTitle();
                    bookCacheEntity.setChapterId(maxChapterId);
                    bookCacheEntity.setChapterTitle(maxChapterTitle);
                }
                bookCacheEntity.setCacheTime(new Date());;
                bookCacheRepository.save(bookCacheEntity);

                try {
                    buff.close();
                    outStr.close();
                } catch (IOException e) {
                    throw new SelfException("关闭流时出错："+e);
                }

                log.info(bookName+"缓存完成，当前时间："+sd.format(new Date()));
            } catch (Exception e){
                throw new SelfException("生成txt出错:"+e);
            } finally {
                countDownLatch.countDown();
            }
        }
    }

    @Override
    public List<BookVO> getCacheBookList() {
        List<BookVO> cacheBookList = bookCacheMapper.getCacheBookList();
        return cacheBookList;
    }

    public void copyFile(InputStream input, OutputStream output) throws IOException {
        byte aByte;
        while((aByte = (byte)input.read()) != -1) {
            output.write(aByte);
        }
    }

    public static void main(String[] args) {
        int size = 201;
        double x = size*0.1;
        int as = (int) Math.ceil(x);
        System.out.println(as);
    }
}